package com.aliengen.thingple.driverapp.device;

import android.content.Context;
import android.os.Handler;
import android.util.Log;

import com.aliengen.thingple.cmc168mwithservice.Common;
import com.ftdi.j2xx.D2xxManager;
import com.ftdi.j2xx.FT_Device;
import com.handset.Device;

/**
 * This class is part of the Thingple mobile application for the CMC168 Handheld reader.
 *
 * Copyright AlienGen Limited 2016. All rights reserved.
 *
 * @author Timothé Mermet-Buffet <tim@aliengen.com>
 */
public class ThingpleDevice {
    public static D2xxManager ftD2xx = null;
    protected Context FT_Context;
    protected Device device;

    protected CMCHandler handler;

    private int portIndex = 0;
    private int DevCount = -1;
    private int currentPortIndex = -1;

    public ThingpleDevice(Context context, Handler handler)
    {
        try
        {
            ftD2xx = D2xxManager.getInstance(context);
            FT_Context = context;
        }
        catch (D2xxManager.D2xxException e)
        {
            Log.e("TT", "getInstance fail!!");
        }

        device = new Device(ftD2xx, context, handler);

        if(!this.device.getDeviceIsOpen()) {
            this.createDeviceList();
            if (this.DevCount > 0) {
                this.connectFunction();
            }
        }
    }

    private void createDeviceList() {
        int tempDevCount = ftD2xx.createDeviceInfoList(this.FT_Context);
        if(tempDevCount > 0) {
            if(this.DevCount != tempDevCount) {
                this.DevCount = tempDevCount;
            }
        } else {
            this.DevCount = -1;
            this.currentPortIndex = -1;
        }
    }

    void connectFunction() {
        if(this.portIndex + 1 > this.DevCount) {
            this.portIndex = 0;
        }
        FT_Device ftDev = ftD2xx.openByIndex(FT_Context, this.portIndex);

        if(this.currentPortIndex != this.portIndex || ftDev == null || !ftDev.isOpen()) {
            if(ftDev == null) {
                ftDev = ftD2xx.openByIndex(this.FT_Context, this.portIndex);
            } else {
                ftDev = ftD2xx.openByIndex(this.FT_Context, this.portIndex);
            }

            if(ftDev != null) {
                if(ftDev.isOpen()) {
                    this.currentPortIndex = this.portIndex;
                }
            }
        }
    }

    public void onConnect()
    {
        Log.i("ThingpleDevice", "setModeActive: false");
        this.device.setModeActive(false);
        Log.i("ThingpleDevice", "activePowerOff");
        this.device.activePowerOff();
        Log.i("ThingpleDevice", "idCardPowerOff");
        this.device.idCardPowerOff();
        Log.i("ThingpleDevice", "barcodePowerOff");
        this.device.barcodePowerOff();
        Log.i("ThingpleDevice", "fingerprintPowerOff");
        this.device.fingerprintPowerOff();
        Log.i("ThingpleDevice", "hfPowerOff");
        this.device.hfPowerOff();

        Log.i("ThingpleDevice", "setInventoryHex: true");
        this.device.setInventoryHex(true);

        Log.i("ThingpleDevice", "setReadWriteHex: true");
        this.device.setReadWriteHex(true);

        Log.i("ThingpleDevice", "uhfPowerOn");
        this.device.uhfPowerOn();
        try {
            Thread.sleep(200);
        } catch(InterruptedException e) {
            e.printStackTrace();
        }


        Log.i("ThingpleDevice", "setSendAlive: true");
        this.device.setSendAlive(true);

        /**
         * Activate the thread for UHF.
         */
        Log.i("ThingpleDevice", "setModeUB: true");
        this.device.setModeUB(true);
        try {
            Thread.sleep(200);
        } catch(InterruptedException e) {
            e.printStackTrace();
        }

        /**
         * Unselect in case of previous selection.
         */
        this.device.exitSelect();
    }

    public void setHandler(CMCHandler handler)
    {
        Log.i("ThingpleDevice", "setHandler");
        this.handler = handler;
        this.device.setHandler(handler);
    }

    public void onDisconnect()
    {
        Log.i("ThingpleDevice", "setModeUB: false");
        this.device.setModeUB(false);
    }

    public void setPower(int power)
    {
        Log.i("ThingpleDevice", "setUhfPower: " + power);
        this.device.setUhfPower(power*10, 200, 300);
        try {
            Thread.sleep(10L);
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
    }

    boolean inventory = false;

    public void startInventory()
    {
        Log.i("ThingpleDevice", "uhfInventory");
        if(inventory == false) {
            this.device.uhfInventory();
            inventory = true;
        }
        try {
            Thread.sleep(10L);
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void stopInventory()
    {
        Log.i("ThingpleDevice", "uhfStopInventory");
        if(inventory == true) {
            this.device.uhfStopInventory();
            inventory = false;
        }
        try {
            Thread.sleep(10L);
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
    }

    public int getSize()
    {
        int size =  this.device.getSize();
        Log.i("ThingpleDevice", "getSize = " + size);
        return size;
    }

    public String getItem()
    {
        Log.i("ThingpleDevice", "getItem");
        return this.device.getItem().substring(5);
    }

    public void resetItems()
    {
        Log.i("ThingpleDevice", "queue.clear()");
        this.device.queue.clear();
    }

    public boolean getDeviceIsOpen()
    {
        Log.i("ThingpleDevice", "getDeviceIsOpen");
        return this.device.getDeviceIsOpen();
    }

    public void select(byte[] epc, int timeout)
    {
        Log.i("ThingpleDevice", "Select EPC: " + Common.arrByte2String(epc, 0, epc.length));

        this.handler.setTimer(CMCHandler.SELECT_TIMEOUT, timeout);

        int length = epc.length;
        // Bank, Offset, Length, Bytes
        this.device.setSelect(1, 4 * 8, epc.length * 8, epc);
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
//        this.device.setSelect(1, 4 * 8, epc.length * 8, epc);
        //this.device.setSelect(1, 4 * 8, (length / 2) * 8, epc);
    }

    public void unselect()
    {
        Log.i("ThingpleDevice", "unselect");
        this.device.exitSelect();
    }

    public void read(int timeout)
    {
        Log.i("ThingpleDevice", "read");
        byte[] password = {0, 0, 0, 0, 0, 0, 0, 0};

        password[0] = password[7];
        password[1] = password[6];
        password[2] = password[5];
        password[3] = password[4];

        this.handler.setTimer(CMCHandler.READ_TIMEOUT, timeout);
        this.device.readUhfTag(1, 0, 1, password);
    }

    public void write(byte[] epc, int timeout)
    {
        Log.i("ThingpleDevice", "write");
        byte[] password = {0, 0, 0, 0, 0, 0, 0, 0};

        password[0] = password[7];
        password[1] = password[6];
        password[2] = password[5];
        password[3] = password[4];

        byte[] writeData = new byte[128];
        for (int i = 0; i < 128; i++) {
            writeData[i] = 0;
        }

        for (int i = 0; i < epc.length; i++) {
            writeData[i] = epc[i];
        }

        Log.i("ThingpleDevice", "EPC: " + Common.arrByte2String(writeData, 0, writeData.length));
        Log.i("ThingpleDevice", "Writing " + epc.length + " byte(s)!");

        this.handler.setTimer(CMCHandler.WRITE_TIMEOUT, timeout);
        this.device.writeUhfTag(1, 2, epc.length, password, writeData);
    }
}
